package com.dynamic.model.common.dao.impl;


import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import com.dynamic.model.common.dao.BaseDao;
import com.dynamic.model.common.vo.Page;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate4.HibernateTemplate;

import com.dynamic.model.common.entity.BaseEntity;
import com.dynamic.model.util.common.GenericUtil;

public class BaseDaoImpl<E extends BaseEntity> extends HibernateTemplate implements BaseDao<E> {
	
	private Logger log = Logger.getLogger(this.getClass());
	
	protected Class<E> clazz;

	@Override
	@Resource
	public void setSessionFactory(SessionFactory sessionFactory) {
		super.setSessionFactory(sessionFactory);
	}
	
	@SuppressWarnings("unchecked")
	public BaseDaoImpl() {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
					clazz = GenericUtil.getActualClass(this.getClass(), 0);
		} catch (Exception e) {
			log.error("base dao can not get  clazz!", e);
		}
	}

	@Override
	public void saveOrUpdate(E entity) throws Exception {
		this.getSessionFactory().getCurrentSession().saveOrUpdate(entity);
	}

	
	@Override
	public List<E> getAll(String orderBy) {
		if (orderBy == null) {
			orderBy = " createTime ";
		}
		String hql = "from " + this.clazz.getName() + "  where deleteFlag=0  order by " + orderBy;
		return this.getSessionFactory().getCurrentSession().createQuery(hql).list();
	}

	@Override
	public List<E> getAll() {
		String hql = "from " + this.clazz.getName() + "  where deleteFlag=0  order by createTime" ;
		return this.getSessionFactory().getCurrentSession().createQuery(hql).list();
	}

	@Override
	public E queryForObject(String hql, Object[] parameters) {
		Query query = this.getSessionFactory().getCurrentSession().createQuery(hql);
		if (parameters != null) {
			for (int i = 0, len = parameters.length; i < len; i++) {
				query.setParameter(i, parameters[i]);
			}
		}
		return (E) query.uniqueResult();
	}

	@Override
	public E get(Integer pid) {
		String hql = "from " + this.clazz.getName() + "  where deleteFlag=0 and pid=?";
		Query query = this.getSessionFactory().getCurrentSession().createQuery(hql);
		query.setInteger(0, pid);
		return (E)query.uniqueResult();
	}

	@Override
	public int getRowCountByDetachedCriteria(DetachedCriteria condition) {
		Criteria criteria = condition.getExecutableCriteria(this.getSessionFactory().getCurrentSession());
		Long totalCount = (Long) criteria.setProjection(Projections.rowCount()).uniqueResult();
		return totalCount == null ? 0 : totalCount.intValue();
	}

	@Override
	public List<E> findByDetachedCriteria(DetachedCriteria condition, int page, int rows) {
		Criteria criteria = condition.getExecutableCriteria(this.getSessionFactory().getCurrentSession());
		criteria.setFirstResult((page - 1) * rows).setMaxResults(rows);
		criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
		return criteria.list();
	}

	@Override
	public void save(E entity) throws Exception {
		this.getSessionFactory().getCurrentSession().save(entity);
	}

	@Override
	public void update(E entity) throws Exception {
		this.getSessionFactory().getCurrentSession().update(entity);
	}

	@Override
	public void deleteLogicByIds(String[] pidArray) throws Exception {
		String hql ="update  "+this.clazz.getName()+" t set   t.deleteFlag = ?  where t.pid in ( :pids ) " ;
		
		Query query = this.getSessionFactory().getCurrentSession().createQuery(hql);
		
		query.setInteger(0, BaseEntity.DELETE_FLAG_YES);
		
		List<Integer> _tempList = new ArrayList<Integer>();
		for(int i = 0; i < pidArray.length ; i++){
			_tempList.add(Integer.parseInt(pidArray[i]));
		}
		
		query.setParameterList("pids", _tempList);
		
		query.executeUpdate();
	}
	protected List<E> queryForList(String hql, List<Object> params, Page<E> page) {
        generatePageTotalCount(hql, params, page);
        Query query = this.getSessionFactory().getCurrentSession().createQuery(hql);
        if (params != null) {
			for (int i = 0, len = params.size(); i < len; i++) {
				query.setParameter(i, params.get(i));
			}
		} 
        query.setFirstResult(page.getOffset());  
        query.setMaxResults(page.getLimit());  
        return query.list();  
    }  
  
    /** 
     * 该方法会改变参数page的totalCount字段 
     *  
     * @param originHql 
     *            原始hql语句 
     * @param params 
     *            原始参数 
     * @param page 
     *            页面对象 
     */  
    private void generatePageTotalCount(String originHql, List<Object> params,Page<E> page) {  
        String generatedCountHql = "select count(*) " + originHql;  
        Query countQuery = this.getSessionFactory().getCurrentSession().createQuery(generatedCountHql);  
        if (params != null) {
			for (int i = 0, len = params.size(); i < len; i++) {
				countQuery.setParameter(i, params.get(i));
			}
		} 
        int totalCount = ((Long) countQuery.uniqueResult()).intValue();  
        page.setTotal((long)totalCount);  
    }

	@Override
	public void saveAndCommit(E entity) throws Exception {
		Session session = this.getSessionFactory().openSession();
		Transaction tx = session.beginTransaction();
		try {
			session.save(entity);
			tx.commit(); 
		} catch (Exception ef) {
			if (null != tx) {
				tx.rollback();
				ef.printStackTrace();
			}
		}finally {
			session.flush();
			session.close();
		}
	}

	@Override
	public void updateAndCommit(E entity) throws Exception {
		Session session = this.getSessionFactory().openSession();
		Transaction tx = session.beginTransaction();
		try {
			/*session.update(entity);*/
			session.merge(entity);
			tx.commit(); 
		} catch (Exception ef) {
			if (null != tx) {
				tx.rollback();
				ef.printStackTrace();
			}
		}finally {
			session.flush();
			session.close();
		}
	}
}
